#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
#include <linux/limits.h>
#include <linux/string.h>
#include <linux/file.h>
#include <linux/fs.h>
#include <linux/net.h>
#if defined(TK4) || defined(TK4_NEW)
#include <linux/genhd.h>
#else
#include <linux/blkdev.h>
#endif
#include <net/sock.h>
#include <target/target_core_base.h>
#include "kprobe_prehook.h"
#include "syms.h"
#include "./include/kernel/sched/sched.h"
#include "./include/drivers/target/target_core_file.h"
#include "./include/drivers/block/loop.h"

#define shm_file_data(file) (*((struct shm_file_data **)&(file)->private_data))
extern unsigned int sysctl_module_debug;
struct shm_file_data {
    int id;
    struct ipc_namespace *ns;
    struct file *file;
    const struct vm_operations_struct *vm_ops;
};
bool sub_print_func_name(void *opt, void *opt2, void *opt3, char *pointer, char *func)
{
	bool ret = true;


	if ((check_func_name("nobh_truncate_page") || check_func_name("do_read_cache_page") || check_func_name("read_pages"))
		&& strstr(pointer, "mapping->a_ops->readpage")) {
		struct address_space *mapping = (struct address_space *)opt;
		sprintf(func, "%pF", mapping->a_ops->readpage);
		return ret;
	}
	if ((check_func_name("generic_file_buffered_read")) && strstr(pointer, "mapping->a_ops->readpage")) {
		struct kiocb *iocb = (struct kiocb *)opt;
		struct file *filp = iocb->ki_filp;
		struct address_space *mapping = filp->f_mapping;
		sprintf(func, "%pF", mapping->a_ops->readpage);
		return ret;
	}
	if ((check_func_name("filemap_fault")) && strstr(pointer, "mapping->a_ops->readpage")) {
		struct vm_fault *vmf = (struct vm_fault *)opt;
		struct file *file = vmf->vma->vm_file;
		struct address_space *mapping = file->f_mapping;
		sprintf(func, "%pF", mapping->a_ops->readpage);
		return ret;
	}
	if ((check_func_name("filemap_fault")) && strstr(pointer, "mapping->a_ops->readpage")) {
		struct vm_fault *vmf = (struct vm_fault *)opt;
		struct file *file = vmf->vma->vm_file;
		struct address_space *mapping = file->f_mapping;
		sprintf(func, "%pF", mapping->a_ops->readpage);
		return ret;
	}
	if (check_func_name("read_pages") && strstr(pointer, "mapping->a_ops->readpages")) {
		struct address_space *mapping = (struct address_space *)opt;
		if (mapping->a_ops->readpages)
			sprintf(func, "%pF", mapping->a_ops->readpages);
		return ret;
	}
	if ((check_func_name("writeout")) && strstr(pointer, "mapping->a_ops->writepage")) {
		struct address_space *mapping = (struct address_space *)opt;
		if (mapping && mapping->a_ops->writepage)
			sprintf(func, "%pF", mapping->a_ops->writepage);
		return ret;
	}
	if ((check_func_name("__writepage")) && strstr(pointer, "mapping->a_ops->writepage")) {
		struct address_space *mapping = (struct address_space *)opt3;
		if (mapping && mapping->a_ops->writepage)
			sprintf(func, "%pF", mapping->a_ops->writepage);
		return ret;
	}
	if ((check_func_name("pageout")) && strstr(pointer, "mapping->a_ops->writepage")) {
		struct address_space *mapping = (struct address_space *)opt2;
		if (mapping && mapping->a_ops->writepage)
			sprintf(func, "%pF", mapping->a_ops->writepage);
		return ret;
	}
	if ((check_func_name("set_page_dirty")) && strstr(pointer, "spd")) {
		struct page *page = (struct page *)opt;
		struct address_space *mapping = page_mapping(page);
		if (mapping && mapping->a_ops->set_page_dirty)
			sprintf(func, "%pF", mapping->a_ops->set_page_dirty);
		return ret;
	}
	if ((check_func_name("ext4_writepage")) && strstr(pointer, "inode->i_mapping->a_ops->invalidatepage")) {
		struct page *page = (struct page *)opt;
		struct inode *inode = page->mapping->host;
		sprintf(func, "%pF", inode->i_mapping->a_ops->invalidatepage);
		return ret;
	}
	if ((check_func_name("do_invalidatepage")) && strstr(pointer, "invalidatepage")) {
		struct page *page = (struct page *)opt;
		if (page->mapping->a_ops->invalidatepage)
			sprintf(func, "%pF", page->mapping->a_ops->invalidatepage);
		return ret;
	}
	if ((check_func_name("try_to_release_page")) && strstr(pointer, "mapping->a_ops->releasepage")) {
		struct page *page = (struct page *)opt;
		struct address_space * const mapping = page->mapping;
		if (mapping && mapping->a_ops->releasepage)
			sprintf(func, "%pF", mapping->a_ops->releasepage);
		return ret;
	}
	if ((check_func_name("move_to_new_page")) && strstr(pointer, "mapping->a_ops->migratepage")) {
		struct page *page = (struct page *)opt2;
		struct address_space * const mapping = page->mapping;
		if (mapping && mapping->a_ops->migratepage)
			sprintf(func, "%pF", mapping->a_ops->migratepage);
		return ret;
	}
	if (check_func_name("check_preempt_curr") && strstr(pointer, "rq->curr->sched_class->check_preempt_curr")) {
		struct rq *rq = (struct rq *)opt;
		sprintf(func, "%pF", rq->curr->sched_class->check_preempt_curr);
		return ret;
	}
	if (check_func_name("kernel_sendpage") && strstr(pointer, "sock->ops->sendpage")) {
		struct socket *sock = (struct socket *)opt;
		if (sock->ops->sendpage)
			sprintf(func, "%pF", sock->ops->sendpage);
		return ret;
	}
	if (check_func_name("kernel_sendpage_locked") && strstr(pointer, "sock->ops->sendpage_locked")) {
		struct socket *sock = (struct socket *)opt;
		if (sock->ops->sendpage_locked)
			sprintf(func, "%pF", sock->ops->sendpage_locked);
		return ret;
	}
	if (check_func_name("inet_sendpage") && strstr(pointer, "sk->sk_prot->sendpage")) {
		struct socket *sock = (struct socket *)opt;
		struct sock *sk = sock->sk;
		if (sk->sk_prot->sendpage)
			sprintf(func, "%pF", sk->sk_prot->sendpage);
		return ret;
	}

	return false;
}
